package com.elias.share.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.util.StrUtil;
import com.elias.share.config.bean.FileInfo;
import com.elias.share.constants.Contants;
import com.elias.share.enums.WebResultMsgEnum;
import com.elias.share.exception.BusinessException;
import com.elias.share.service.IFileService;
import com.elias.share.utils.FileDeleteQueueUtil;
import com.elias.share.utils.WebResultUtil;
import com.elias.share.vo.WebResultVo;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;

@Log4j2
@Service
public class FileServiceImpl implements IFileService {

    @Resource
    private FileInfo fileInfo;

    @Override
    public WebResultVo<String> uploadFile(MultipartFile file, Integer expireTime) {
        if (expireTime < fileInfo.getMinExpireTime() || expireTime > fileInfo.getMaxExpireTime()) {
            return WebResultUtil.fail(String.format("过期时间需要在%d-%d分钟之间", fileInfo.getMinExpireTime(), fileInfo.getMaxExpireTime()));
        }
        boolean isSuccess = fileInfo.addUsedSize(file.getSize());
        if (!isSuccess) {
            log.error("the dir size has exceeded limit,can't upload file");
            return WebResultUtil.fail(WebResultMsgEnum.SYSTEM_SIZE_EXCEED_LIMIT.getMessage());
        }
        long millis = System.currentTimeMillis();
        String uploadFileName = file.getOriginalFilename();
        String suffixName = FileUtil.getSuffix(uploadFileName);
        String newFileName = String.valueOf(millis + expireTime * 60 * 1000);
        if (StrUtil.isNotEmpty(suffixName)) {
            newFileName = newFileName + Contants.STR_POINT + suffixName;
        }
        LocalDateTime localDateTime = LocalDateTimeUtil.of(millis);
        int month = localDateTime.getMonth().getValue();
        int day = localDateTime.getDayOfMonth();
        int hour = localDateTime.getHour();
        Path filePath = Paths.get(
                fileInfo.getLocation(),
                String.valueOf(month),
                String.valueOf(day),
                String.valueOf(hour),
                newFileName);
        try {
            FileUtil.mkParentDirs(filePath);
            file.transferTo(filePath);
        } catch (IOException e) {
            log.error("file transfer error,e:", e);
            fileInfo.minusUsedSize(file.getSize());
            return WebResultUtil.error(WebResultMsgEnum.SYSTEM_ERROR.getMessage());
        }
        return WebResultUtil.success(String.format("/file/download/%d/%d/%d/%s", month, day, hour, newFileName));
    }

    @Override
    public void downloadFile(Path path, HttpServletResponse response) {
        Path absolutPath = Paths.get(fileInfo.getLocation()).resolve(path);
        File file = absolutPath.toFile();
        if (!file.exists() || file.isDirectory()) {
            throw new BusinessException(WebResultMsgEnum.FILE_NOT_FOUND_OR_EXPIRED.getMessage());
        }
        String fileName = file.getName();
        String millis = fileName;
        int pointIndex = fileName.indexOf(Contants.STR_POINT);
        if (pointIndex >= 0) {
            millis = fileName.substring(0, pointIndex);
            if (StrUtil.isEmpty(millis)) {
                throw new BusinessException(WebResultMsgEnum.PARAM_ERROR.getMessage());
            }
        }
        if (!millis.matches("^[1-9][0-9]+$")) {
            throw new BusinessException(WebResultMsgEnum.PARAM_ERROR.getMessage());
        }
        if (System.currentTimeMillis() > Long.parseLong(millis)) {
            FileDeleteQueueUtil.offer(absolutPath);
            throw new BusinessException(WebResultMsgEnum.FILE_NOT_FOUND_OR_EXPIRED.getMessage());
        }
        log.info("donwload file start,path:{},size:{}", file.getAbsoluteFile(), DataSizeUtil.format(file.length()));
        try {
            //设置输出流的格式
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            response.setContentType("application/octet-stream");

            // 读取文件的字节流
            FileInputStream fis = new FileInputStream(file);
            byte[] buff = new byte[1024 * 8];
            OutputStream os = response.getOutputStream();
            int i = 0;
            while ((i = fis.read(buff)) != -1) {
                os.write(buff, 0, i);
                os.flush();
            }
            fis.close();
            os.close();
        } catch (IOException e) {
            log.error("donwload file exception", e);
            throw new BusinessException(WebResultMsgEnum.SYSTEM_ERROR.getMessage());
        }
        log.info("download success,path: " + file.getAbsoluteFile());
    }
}
